using System;
using System.Collections.Generic;
using System.IO;
using EntityKit.Runtime;
using UnityEditor;
using UnityEngine;
using UnityEngine.UIElements;
using AssetDatabase = UnityEditor.AssetDatabase;
using Event = UnityEngine.Event;
using EventType = UnityEngine.EventType;

namespace EntityKit.Editor
{
    public class GameSettingProvider : SettingsProvider
    {
        private SerializedObject _gameSettingSerializedObject;
        private GameSettingConfig _gameSetting;
        private PagePainter _pagePainter;
        private string _defaultPath = "Assets/Resources/Configs/ScriptableObject/GameSettingConfig.asset";

        private GameSettingProvider(string path, SettingsScope scopes, IEnumerable<string> keywords = null) : base(path, scopes, keywords)
        {
        }
        
        public static void OpenSettings()
        {
            SettingsService.OpenProjectSettings("GameSetting");
        }

        [SettingsProvider]
        private static SettingsProvider CreateSettingProvider()
        {
            return new GameSettingProvider("GameSetting", SettingsScope.Project)
            {
                keywords = GetSearchKeywordsFromGUIContentProperties<GameSettingConfig>()
            };
        }

        public override void OnActivate(string searchContext, VisualElement rootElement)
        {
            base.OnActivate(searchContext, rootElement);
            _gameSetting = ScriptableObjectHelper.LoadOrCreateSingletonScriptableObject<GameSettingConfig>(_defaultPath);
            _gameSettingSerializedObject = new SerializedObject(_gameSetting);
            _pagePainter = new PagePainter(nameof(GameSettingProvider));
            _pagePainter.AddPage("Scripting Define", EditorGUIUtility.IconContent("UnityEditor.ConsoleWindow").image, ScriptingDefineGUI);
            _pagePainter.AddPage("Setting", EditorGUIUtility.IconContent("SettingsIcon").image, SettingGUI);
            //_pagePainter.AddPage("Gen Script", EditorGUIUtility.IconContent("SceneViewOrtho").image, GenScriptGUI);
            //_pagePainter.AddPage("HybridCLR", EditorGUIUtility.IconContent("Update-Available").image, HybridCLRGUI);
            //_pagePainter.AddPage("Config Table", EditorGUIUtility.IconContent("UnityEditor.AnimationWindow").image, ConfigTableGUI);
            //_pagePainter.AddPage("Gen Script3", EditorGUIUtility.IconContent("UnityEditor.HierarchyWindow").image, ScriptingDefineGUI);


            ScriptingDefineEnable();
            EditorApplication.update += ForceContinuousRepaint;
        }

        public override void OnDeactivate()
        {
            if (_gameSettingSerializedObject != null && _gameSettingSerializedObject.hasModifiedProperties)
            {
                AssetDatabase.SaveAssets();
                AssetDatabase.Refresh();
            }

            EditorApplication.update -= ForceContinuousRepaint;
            base.OnDeactivate();
        }

        public override void OnGUI(string searchContext)
        {
            _gameSettingSerializedObject.Update();
            _pagePainter.Painting();
            _gameSettingSerializedObject.ApplyModifiedProperties();
            ForceImmediateRepaint();
        }

        private void ForceContinuousRepaint()
        {
            var window = EditorWindow.focusedWindow;
            if (window != null && window.titleContent.text == "Project Settings")
            {
                window.Repaint();
            }
        }

        private void ForceImmediateRepaint()
        {
            if (Event.current.type == UnityEngine.EventType.Layout)
            {
                GUI.changed = true;
                EditorWindow.focusedWindow?.Repaint();
            }
        }

        private void PropertyField(string propertyName, string name, bool isLine = true, params GUILayoutOption[] options)
        {
            if (isLine) EditorGUILayout.BeginHorizontal();

            var serializedProperty = _gameSettingSerializedObject.FindProperty(propertyName);
            if (serializedProperty != null)
            {
                EditorGUILayout.PropertyField(serializedProperty, new GUIContent(name), true, options);
            }
            else
            {
                EditorGUILayout.HelpBox($"Property [{propertyName}] not found!", MessageType.Error);
            }

            if (isLine) EditorGUILayout.EndHorizontal();
        }

        #region ScriptingDefine

        private ScriptingDefine _currentScriptingDefine;
        private bool _isNewDefine = false;
        private string _newDefine = "";
        private GUIContent _predefinedGC;
        private static readonly string ScriptingDefine_Record = "ScriptingDefineRecord";

        private void ScriptingDefineEnable()
        {
            _currentScriptingDefine = new ScriptingDefine();
            _predefinedGC = new GUIContent();
        }

        private void ScriptingDefineGUI()
        {
            GUILayout.BeginHorizontal();
            GUILayout.FlexibleSpace();
            EditorGUILayout.LabelField("Defined");
            GUILayout.FlexibleSpace();
            GUILayout.EndHorizontal();

            GUILayout.BeginHorizontal();
            GUI.enabled = false;
            EditorGUILayout.TextField(_currentScriptingDefine.Defined);
            GUI.enabled = true;
            GUILayout.EndHorizontal();

            GUILayout.BeginHorizontal();
            GUI.enabled = _currentScriptingDefine.IsAnyDefined;
            GUI.backgroundColor = Color.red;
            if (GUILayout.Button("Remove", "ButtonLeft"))
            {
                GenericMenu gm = new GenericMenu();
                foreach (var item in _currentScriptingDefine.Defineds)
                {
                    gm.AddItem(new GUIContent(item), false, () => { _currentScriptingDefine.RemoveDefine(item); });
                }

                gm.ShowAsContext();
            }

            if (GUILayout.Button("Clear", "ButtonMid"))
            {
                _currentScriptingDefine.ClearDefines();
            }

            GUI.enabled = true;
            GUI.backgroundColor = Color.yellow;
            if (GUILayout.Button("New", "ButtonMid"))
            {
                _isNewDefine = !_isNewDefine;
                _newDefine = "";
            }

            if (GUILayout.Button("Apply", "ButtonRight"))
            {
                _currentScriptingDefine.Apply();
            }

            GUI.backgroundColor = Color.white;
            GUILayout.EndHorizontal();

            if (_isNewDefine)
            {
                GUILayout.BeginHorizontal();
                _newDefine = EditorGUILayout.TextField(_newDefine);
                if (GUILayout.Button("OK", EditorStyles.miniButtonLeft, GUILayout.Width(30)))
                {
                    if (!string.IsNullOrEmpty(_newDefine))
                    {
                        _currentScriptingDefine.AddDefine(_newDefine);
                        _isNewDefine = false;
                        _newDefine = "";
                    }
                    else
                    {
                        Debug.LogError("输入的脚本定义不能为空！");
                    }
                }

                if (GUILayout.Button("NO", EditorStyles.miniButtonRight, GUILayout.Width(30)))
                {
                    _isNewDefine = false;
                    _newDefine = "";
                }

                GUILayout.EndHorizontal();

                GUILayout.Space(5);

                GUILayout.BeginHorizontal();
                EditorGUILayout.LabelField("Predefined:");
                GUILayout.EndHorizontal();

                DrawPredefined("DISABLE_ASPECTTRACK", "禁用 AspectTrack 模块");
                DrawPredefined("DISABLE_BUILDER", "禁用框架构建器");
                DrawPredefined("HOTFIX_HybridCLR", "启用 HybridCLR 热更新");

                GUILayout.Space(5);

                GUILayout.BeginHorizontal();
                EditorGUILayout.LabelField("Historical Record:");
                GUILayout.FlexibleSpace();
                if (GUILayout.Button("Clear Record", GUILayout.Width(90)))
                {
                    _currentScriptingDefine.ClearDefinesRecord();
                }

                GUILayout.EndHorizontal();

                for (int i = 0; i < _currentScriptingDefine.DefinedsRecord.Count; i++)
                {
                    GUILayout.BeginHorizontal();
                    GUILayout.Space(10);
                    GUI.enabled = !_currentScriptingDefine.Defined.Contains(_currentScriptingDefine.DefinedsRecord[i]);
                    GUILayout.Label(_currentScriptingDefine.DefinedsRecord[i], "PR PrefabLabel");
                    GUILayout.FlexibleSpace();
                    if (GUILayout.Button("Use", GUILayout.Width(40)))
                    {
                        _newDefine += $"{_currentScriptingDefine.DefinedsRecord[i]};";
                    }

                    GUI.enabled = true;
                    GUILayout.EndHorizontal();
                }
            }
        }

        private void DrawPredefined(string define, string tooltip)
        {
            GUILayout.BeginHorizontal();
            GUILayout.Space(10);
            _predefinedGC.text = define;
            _predefinedGC.tooltip = tooltip;
            GUI.enabled = !_currentScriptingDefine.Defined.Contains(define);
            GUILayout.Label(_predefinedGC, "PR PrefabLabel");
            GUILayout.FlexibleSpace();
            if (GUILayout.Button("Use", GUILayout.Width(40)))
            {
                _newDefine += $"{define};";
            }

            GUI.enabled = true;
            GUILayout.EndHorizontal();
        }

        private sealed class ScriptingDefine
        {
            /// <summary>
            /// 宏定义记录
            /// </summary>
            public List<string> DefinedsRecord { get; } = new List<string>();

            /// <summary>
            /// 宏定义
            /// </summary>
            public HashSet<string> Defineds { get; } = new HashSet<string>();

            /// <summary>
            /// 宏定义记录
            /// </summary>
            public string DefinedRecord { get; private set; } = "";

            /// <summary>
            /// 宏定义
            /// </summary>
            public string Defined { get; private set; } = "";

            /// <summary>
            /// 是否存在任意宏定义
            /// </summary>
            public bool IsAnyDefined
            {
                get { return !string.IsNullOrEmpty(Defined); }
            }

            public ScriptingDefine()
            {
                AddDefineRecord(EditorPrefs.GetString(ScriptingDefine_Record, null));

                BuildTargetGroup buildTargetGroup =
                    BuildPipeline.GetBuildTargetGroup(EditorUserBuildSettings.activeBuildTarget);
                AddDefine(PlayerSettings.GetScriptingDefineSymbolsForGroup(buildTargetGroup));
            }

            /// <summary>
            /// 添加宏定义
            /// </summary>
            public void AddDefine(string define)
            {
                if (string.IsNullOrEmpty(define))
                    return;

                string[] defines = define.Split(';');
                for (int i = 0; i < defines.Length; i++)
                {
                    if (!string.IsNullOrEmpty(defines[i]) && !Defineds.Contains(defines[i]))
                    {
                        Defined += $"{defines[i]};";
                        Defineds.Add(defines[i]);
                    }
                }

                AddDefineRecord(define);
            }

            /// <summary>
            /// 移除宏定义
            /// </summary>
            public void RemoveDefine(string define)
            {
                if (string.IsNullOrEmpty(define))
                    return;

                if (Defineds.Contains(define))
                {
                    Defined = Defined.Replace($"{define};", "");
                    Defineds.Remove(define);
                }
            }

            /// <summary>
            /// 清空所有宏定义
            /// </summary>
            public void ClearDefines()
            {
                Defined = "";
                Defineds.Clear();
            }

            /// <summary>
            /// 应用宏定义
            /// </summary>
            public void Apply()
            {
                BuildTargetGroup buildTargetGroup =
                    BuildPipeline.GetBuildTargetGroup(EditorUserBuildSettings.activeBuildTarget);
                PlayerSettings.SetScriptingDefineSymbolsForGroup(buildTargetGroup, Defined);
            }

            /// <summary>
            /// 清空宏定义记录
            /// </summary>
            public void ClearDefinesRecord()
            {
                DefinedRecord = "";
                DefinedsRecord.Clear();
                EditorPrefs.SetString(ScriptingDefine_Record, DefinedRecord);
            }

            private void AddDefineRecord(string define)
            {
                if (string.IsNullOrEmpty(define))
                    return;

                string[] defines = define.Split(';');
                for (int i = 0; i < defines.Length; i++)
                {
                    if (!string.IsNullOrEmpty(defines[i]) && !DefinedsRecord.Contains(defines[i]))
                    {
                        DefinedRecord += $"{defines[i]};";
                        DefinedsRecord.Add(defines[i]);
                    }
                }

                EditorPrefs.SetString(ScriptingDefine_Record, DefinedRecord);
            }
        }

        #endregion

        #region Setting

        private void SettingGUI()
        {
            GUILayout.BeginHorizontal();
            GUILayout.FlexibleSpace();
            EditorGUILayout.LabelField("Log", EditorStyles.boldLabel);
            GUILayout.FlexibleSpace();
            GUILayout.EndHorizontal();
            PropertyField(nameof(_gameSetting.LogSetting), "Log Write Setting");
        }

        #endregion

        #region HybridCLR

        private void HybridCLRGUI()
        {
        }

        #endregion
        
    }
}